using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using AspectCore.Extensions.Reflection;
using netCoreStudy.Attr.QueryAttr;
using netCoreStudy.Entities.Base;
using netCoreStudy.Enum;

namespace netCoreStudy.Express
{
	/// <summary>
	/// where ext 的另一种写法
	/// </summary>
	public static class WhereExt2
	{
		public static IQueryable<TSource> WhereExp2<TSource, TP>(this IQueryable<TSource> queryList, TP parameter)
			where TP : BaseParameter
		{
			Type typeSource = typeof(TSource); // 获取 tSource 类型
			Type typeParameter = parameter.GetType(); // 获取 tParameter 类型
			PropertyReflector[] typeSourceProps = typeSource.GetProps(); // 获取 tSource 下的所有 属性 
			PropertyReflector[] typeParameterProps = typeParameter.GetProps() // 获取 tParameter 下的所有 属性(带where特性的) 
				.Where(x => x.GetCustomAttribute<WhereAttribute>() != null)
				.ToArray();
			// 遍历 tParam 的  属性 
			foreach (PropertyReflector tPProp in typeParameterProps)
			{
				Type type = tPProp.GetPropertyInfo().PropertyType; // 获取 tPProp的类型
				object value = tPProp.GetValue(parameter); // 获取 tPProp 的值
				if (type.PropIsZeroOrNull(value)) continue; // 如果值是0 就跳过 
				// 获取where 特性
				WhereAttribute whereAttr = tPProp.GetCustomAttribute<WhereAttribute>();
				string displayName = whereAttr.DisplayName;
				string blurry = whereAttr.Blurry;
				// 开始拼接表达式树
				ParameterExpression p = Expression.Parameter(typeof(TSource), "p");
				if (displayName != null)
				{
					// p=> p.Name
					MemberExpression left = Expression.Property(p, displayName);
					// p=>p.Name ==SearchKey 的 右边部分 (SearchKey)
					ConstantExpression right = Expression.Constant(value, type);
					// 根据 等式的运算类型 拼起来 p=>p.Name == "嘟嘟" 或者 p=>p.Age>3
					Expression exp = JoinExp(left, right, whereAttr.Query);
					Console.WriteLine(exp);
					Expression<Func<TSource, bool>> lambda = Expression.Lambda<Func<TSource, bool>>(exp, p);
					queryList = queryList.Where(lambda);
				}

				if (blurry != null)
				{
					List<string> propNames = typeSourceProps.Select(x => x.Name).ToList();
					string[] strings = blurry.Split(',').Distinct().ToArray();
					// 检查 类里面 的属性 (大数组)  有没有 完全包含  blurry[](小数组)(大数组是否包含小数组用这个)
					if (strings.All(x => propNames.Contains(x.Split('.')[0])) == false)
						throw new Exception(
							$"{typeParameter.Name},特性里Blurry的{tPProp.Name}这个属性名有问题! {typeSource.Name}类里面 没有 {blurry} 这个属性! ");
					Expression tempExp = Expression.Constant(false);
					foreach (string blurryName in strings)
					{
						string[] split = blurryName.Split('.');
						if (split.Length == 1)
						{
							// p=> p.Name
							Expression left = Expression.Property(p, blurryName);
							//   ToLower()方法 
							MethodInfo methodToLower = typeof(String).GetMethod("ToLower", new Type[] { });
							// 拼成  p=> p.Name.ToLower()
							left = Expression.Call(left, methodToLower);
							// Contains()方法 
							MethodInfo methodContains =
								typeof(String).GetMethod("Contains", new[] {typeof(string)});
							// p=>p.Name ==SearchKey 的 右边部分 (SearchKey)
							ConstantExpression right = Expression.Constant(value.ToString()?.ToLower(), type);
							// 拼成  p=> p.Name.ToLower().Contains(searchKey)
							MethodCallExpression exp = Expression.Call(left, methodContains, right);
							// 累加条件 x=>x.Name.Contains("哈哈") || x.PassWord.Contains("密码") 
							tempExp = Expression.OrElse(tempExp, exp);
						}

						if (split.Length == 2)
						{
							//一级属性
							string oneLv = split[0];
							//二级属性
							string twoLv = split[1];
							// p=> p.Name
							Expression left = Expression.Property(p, oneLv);
							left = Expression.Property(left, twoLv);
							//   ToLower()方法 
							MethodInfo methodToLower = typeof(String).GetMethod("ToLower", new Type[] { });
							// 拼成  p=> p.Name.ToLower()
							left = Expression.Call(left, methodToLower);
							// Contains()方法 
							MethodInfo methodContains =
								typeof(String).GetMethod("Contains", new[] {typeof(string)});
							// p=>p.Name ==SearchKey 的 右边部分 (SearchKey)
							ConstantExpression right = Expression.Constant(value.ToString()?.ToLower(), type);
							// 拼成  p=> p.Name.ToLower().Contains(searchKey)
							MethodCallExpression exp = Expression.Call(left, methodContains, right);
							// 累加条件 x=>x.Name.Contains("哈哈") || x.PassWord.Contains("密码") 
							tempExp = Expression.OrElse(tempExp, exp);
						}

						if (split.Length > 2) throw new Exception("模糊查询不支持3级(User.Image.Name)");
					}

					Console.WriteLine(tempExp);
					Expression<Func<TSource, bool>> lambda = Expression.Lambda<Func<TSource, bool>>(tempExp, p);
					queryList = queryList.Where(lambda);
				}
			}

			return queryList;
		}

		public static Expression JoinExp(MemberExpression left, ConstantExpression right, QueryType queryType)
		{
			//根据查询选择器中该属性的查询条件进行不同的操作	
			//根据 枚举 获取 运算 符
			switch (queryType)
			{
				case QueryType.Equal:
					return Expression.Equal(left, right);
				case QueryType.GreaterThan:
					return Expression.GreaterThan(left, right);
				case QueryType.LessThan:
					return Expression.LessThan(left, right);
				case QueryType.GreaterThanOrEqual:
					return Expression.GreaterThanOrEqual(left, right);
				case QueryType.LessThanOrEqual:
					return Expression.LessThanOrEqual(left, right);
				default:
					throw new ArgumentOutOfRangeException();
			}
		}

}
}